package cn.k7g.alloy.ioc.processor;

import cn.k7g.alloy.annotation.IgnoreEmptyInvoke;
import cn.k7g.alloy.annotation.IgnoreEmptyParam;
import cn.k7g.alloy.autoconfiguration.EnableOptions;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 基于aop实现的忽略调用
 * @author victor-wu
 * @date 2021/9/27 下午1:10
 */
@Slf4j
@Aspect
@Component
@ConditionalOnBean(EnableOptions.EnableIgnoreInvoke.class)
public class IgnoreInvokeAspect {

    @Around("@annotation(ignore)")
    public Object s(ProceedingJoinPoint joinPoint, IgnoreEmptyInvoke ignore) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Parameter[] parameters = method.getParameters();
        Object[] args = joinPoint.getArgs();
        int i = 0;
        for (Parameter parameter : parameters) {
            if (parameter.isAnnotationPresent(IgnoreEmptyParam.class)) {
                boolean valid = true;
                if (args[i] == null) {
                    valid = false;
                } else if (args[i].getClass().isArray() && ((Object[])args[i]).length == 0) {
                    valid = false;
                } else if (args[i] instanceof Collection && ((Collection) args[i]).isEmpty()) {
                    valid = false;
                }
                if (!valid) {
                    log.debug("{} # {} 中参数 {} 为空，忽略执行", joinPoint.getTarget().getClass().getName(), signature.getName(), parameter);
                    return genDefaultReturnValue(method);
                }
            }
            i++;
        }
        return joinPoint.proceed(joinPoint.getArgs());
    }

    private Object genDefaultReturnValue(Method method) {
        Class<?> returnType = method.getReturnType();
        if (Collection.class.isAssignableFrom(returnType)) {
            return new ArrayList<>();
        } else {
            return null;
        }
    }
}
